import time

from pywinauto import Desktop
from pywinauto.findwindows import ElementNotFoundError
from pywinauto.timings import TimeoutError
from tools.logger import log_info, log_error, log_warning


class BindAssertion:
    """
    封装所有 UI 断言方法，用于验证条码绑定系统的操作结果。
    """

    @staticmethod
    def _find_popup_dialog(timeout=5):
        """查找顶级弹窗"""
        desktop = Desktop(backend='win32')
        dialog = desktop.window(title="条码关联系统-提示")
        if dialog.exists(timeout=timeout):
            dialog.wait('visible', timeout=timeout)
            return dialog
        return None

    @staticmethod
    def _close_popup_dialog(dialog):
        """关闭弹窗"""
        try:
            ok_btn = dialog.child_window(title='确定')
            if ok_btn.exists(timeout=2):
                ok_btn.click_input()
                time.sleep(0.2)
                log_info("✅ 已点击【确定】关闭弹窗")
            else:
                log_warning("⚠️ 未找到【确定】按钮，尝试关闭窗口")
                dialog.close()
        except Exception as e:
            log_error(f"⚠️ 关闭弹窗失败: {e}")
            # 尝试强制关闭
            try:
                dialog.close()
            except ElementNotFoundError:
                pass

    @staticmethod
    def _get_popup_text(dialog):
        """提取弹窗中的文本"""
        texts = [
            e.window_text().strip()
            for e in dialog.descendants(auto_id='Tiplbl')
            if e.window_text().strip()
        ]
        return "\n".join(texts).strip()

    @staticmethod
    def assert_binding_success(window):
        """
        断言条码绑定成功：不应出现提示弹窗，且结果显示【通过】
        """
        # 检查是否有错误弹窗（短超时，避免阻塞）
        popup = BindAssertion._find_popup_dialog(timeout=2)
        if popup:
            log_error("❌ 绑定失败！出现了提示弹窗")
            popup_text = BindAssertion._get_popup_text(popup)
            log_error(f"弹窗内容：{popup_text}")
            BindAssertion._close_popup_dialog(popup)
            raise AssertionError("绑定未成功，出现了错误弹窗")

        # 等待并获取绑定结果文本
        try:
            result = window.child_window(title="通过", auto_id="TestResultlbl")
        except ElementNotFoundError:
            raise AssertionError("未找到【TestResultlbl】结果控件，请检查控件ID是否正确")
        try:
            result.wait('visible', timeout=5)
            text = result.window_text().strip()
            assert text == '通过', f"结果不是【通过】：{text}"
            log_info("🎉 断言通过！条码绑定成功")
        except TimeoutError:
            raise AssertionError("❌ 未找到【TestResultlbl】结果控件，可能页面未刷新")
        except ElementNotFoundError:
            raise AssertionError("❌ 未找到绑定结果控件，请检查控件ID是否正确")

    @staticmethod
    def assert_binding_failure(window, expected_reason=None):
        """
        断言绑定失败：
        1. 先处理可能存在的错误弹窗（提取内容、验证原因、关闭）；
        2. 再检查最终结果是否为【失败】。

        弹窗是模态的，必须先关闭才能访问主界面结果。
        """
        popup = BindAssertion._find_popup_dialog(timeout=3)
        if popup:
            log_info("🟡 检测到错误弹窗，正在处理...")
            popup_text = BindAssertion._get_popup_text(popup)
            log_info(f"📋 弹窗内容：\n{popup_text}")

            # 验证失败原因
            if expected_reason:
                failure_keywords = {
                    "already_bound": ["已绑定"],
                    "not_found": ["未查询到", "无测试记录", "未找到"],
                    "format_error": ["条码格式不正确", "条码长度不正确", "非法字符"],
                    "mismatch": ["工单号不匹配", "项目号不匹配", "不一致"],
                    "general_failure": ["失败", "错误", "异常", "不允许", "操作无效"]
                }

                if expected_reason not in failure_keywords:
                    raise ValueError(f"不支持的 expected_reason: {expected_reason}")

                keywords = failure_keywords[expected_reason]
                if not any(kw in popup_text for kw in keywords):
                    BindAssertion._close_popup_dialog(popup)
                    raise AssertionError(
                        f"❌ 预期失败原因 '{expected_reason}'，但弹窗内容不匹配。\n实际内容：{popup_text}"
                    )
                log_info(f"✅ 弹窗内容符合预期失败原因: {expected_reason}")

            # 关闭弹窗
            BindAssertion._close_popup_dialog(popup)

            # 等待弹窗消失
            try:
                popup.wait_not('visible', timeout=5)
            except TimeoutError:
                log_warning("⚠️ 弹窗可能未完全关闭，继续执行...")

        else:
            log_info("ℹ️ 未检测到错误弹窗，直接检查最终结果")

        # === 检查最终结果 ===
        result_label = window.child_window(auto_id="TestResultlbl")
        try:
            result_label.wait('visible', timeout=5)
            result_text = result_label.window_text().strip()
        except Exception as e:
            raise AssertionError(f"❌ 无法获取最终结果控件: {e}")

        if result_text != "失败":
            raise AssertionError(f"❌ 期望绑定失败，但最终结果显示为: 【{result_text}】")

        log_info("🎉 绑定失败断言通过：最终结果为【失败】")
